import { app } from "../../base";
import { Link } from "../../app_base/module/structure/Link";
import { G_Data } from "../DataCenter";
import { ParkAScrewLink } from "../links/ParkAScrewLink";
import { SubgameAdvLink } from "../links/SubgameAdvLink";
import { Recover } from "../component/Recover";
import { GameBgLink } from "../links/GameBgLink";
import { GameBuildLink } from "../links/GameBuildLink";
import { BuildCollectionLink } from "../links/BuildCollectionLink";
import { StartViewLink } from "../links/StartViewLink";
import { GameCoinLink } from "../links/GameCoinLink";
import { CatCatteryLink } from "../links/CatCatteryLink";
import { GameTaskLink } from "../links/GameTaskLink";
import { DailyLink } from "../links/DailyLink";
import { StorageCommonKey } from "../../app_base/module/utils/StorageUtils";
import { ThrowItemGameLink } from "../links/ThrowItemGameLink";
import { LevelLink } from "../links/LevelLink";
import { CatShopLink } from "../links/CatShopLink";
import { CatPretendLink } from "../links/CatPretendLink";
import { ShootItemGameLink } from "../links/ShootItemGameLink";

type StringOrNumber = string | number;

type MeStruct = {
   userName: string;
   userId: string;
   nick?: string;
   coin?: number;
   todaySigned?: boolean;
   firstLoginTime?: number;
   loginDays?: number;
   lastLoginTime?: number;
   version?: string;
   lastUpdate: number;
   lastLogin: number;
   //上次解锁时间
   lastUnlockAllTime: number;
   //解锁看视频次数
   unlockAdTime: number;
}



/**
 * 基础关卡信息
 */
type BaseLevelInfo = {
   id: number;
   type: number;
   prefab: string;
   [key: string]: StringOrNumber;
};

export interface GameLinkInterface {
   /** 是否看了广告 */
   isAdv: boolean;
   /** 关卡解锁列表     */
   unlocks: StringOrNumber[];
   /**
    * 解锁关卡
    * @param level 目标关卡
    */
   unlockLevel(level: StringOrNumber): void;
   /**
    * 关卡是否解锁
    * @param level 目标关卡 
    * @returns 
    */
   isUnlock(level: StringOrNumber): boolean;
   /** 通关关卡列表     */
   passLevels: StringOrNumber[];
   /**
    * 关卡是否通关
    * @param level 目标关卡
    * @returns 
    */
   isPass(level: StringOrNumber): boolean;
   /**
    * 保存通关关卡
    * @param level 目标关卡
    */
   passLevel(level: StringOrNumber): void;

   /**
    * 开始关卡
    * @param id 
    */
   startLevel(id?: StringOrNumber): boolean;

   /**
    * 当前关卡信息
    */
   readonly levelInfo: BaseLevelInfo;
}



/** 游戏类型*/
export enum GameType {
   /** 拆个干净 */
   screw = 1,
   /** 主玩法 */
   parkAndScrew = 2,
   /** 你能行吗 */
   nut = 3,
   /** 我要当状元 */
   word = 4,
   /** 拔钉子 */
   nail = 5,
   /** 铁皮卷卷 */
   iron = 6,
   /** 拖珠子 */
   bead = 8,
   /** 脑洞连线 */
   traffic = 9,
   /** 顺序连线 */
   line = 10,
   /** 割绳子 */
   cutRope = 7,
   /** 脑洞拼图 */
   splice = 11,
   /** 拯救女孩玩法（已废弃） */
   helpGirl = 12,
   /** 快速救援 */
   helpAnimal = 13,
   /** 旅途巴士 */
   park = 14,
   /** 小猪投食 */
   pig = 15,
   /** 染色挑战 */
   drawColor = 16,
   /** 拼图达人 */
   puzzle = 17,
   /** 手指打结 */
   finger = 18,
   /** 找错别字 */
   wrongWord = 19,
   /** 成语猜猜猜 */
   guessIdioms = 20,
   /** 诗词大师 */
   guessPoetry = 21,
   /** 文字添一笔 */
   addAnItem = 23,
   /** 笔画猜字 */
   guessWord = 22,
   /** 齿轮消消 */
   hexagonalMemove = 24,
   /** 螺母分类 */
   screwClassify = 25,
   /** 搭桥闪送 */
   waimai = 26,
   /** 拼房子 */
   housePuzzle = 27,
   /** 接水管 */
   connectHose = 28,
   /** 解开螺母 */
   loosenScrew = 29,
   /** 连电线 */
   connectWire = 30,
   /** 合军旗 */
   chessMilitary = 31,
   /** 珠子分类 */
   digBeads = 32,
   /** 解铁环 */
   ironCircle = 33,
   /** 榨果汁 */
   squeezeJuice = 34,
   /** 幸运乌龟 */
   turtleCollision = 35,
   /** 成语消消消 */
   chengyuPeidui = 36,
   /**保护老鼠 */
   catMice = 37,
   /** 离谱找字 */
   findword = 38,
   /** 水杯子弹作战 */
   bulletCup = 39,
   /** 学诗词 */
   learnPoetry = 40,
   /** 画线圈物 */
   drawLineCircle = 41,
   /** 数字跑酷 */
   digitalParkour = 42,
   /** 俄罗斯方块 */
   tetris = 43,
   /** 倒水种树 */
   growTree = 44,
   /** 补充燃料 */
   refueling = 45,
   /* 连线回家 */
   drawLineHome = 46,
   /* 围鲨鱼 */
   shark = 47,
   /** 画线停车 */
   drawLinePark = 48,
   /* 超级找字 */
   superFindWord = 50,
   /* 超级螺丝分类 */
   superScrewClassify = 49,
   /**密室消除 */
   roomElimination = 51,
   /**抛肉 */
   throwItemGame = 52,
   /**射击老鼠 */
   shootItemGame = 53,
}

/**
 * 当前玩家数据</br>
 * @event G_Data.me.onUpdated 监听玩家所有数据更新
 * @event G_Data.me.coin.onUpdated 监听玩家代币数据更新
 * @event G_Data.me.energy.onUpdated 监听玩家体力数据更新
 */
export class MeVo extends Link<MeStruct> {
   private static created: boolean = false;
   private static ME_INFO_KEY = "MeVo";
   private isFirstLogin: boolean = false;

   constructor() {
      // if (MeVo.created) {
      //    throw new Error("MeVo 为单例");
      // }
      super("me", {
         userName: "",
         userId: "",
         nick: "",
         coin: 0,
         firstLoginTime: 0,
         lastLoginTime: 0,
         loginDays: 0,
         lastUpdate: 0,
         lastLogin: 0,
         lastUnlockAllTime: 0,
         unlockAdTime: 0,
      });
      //游戏开发者，根据游戏业务需求加减数据模块，【数据自动写入本地缓存，无需手动维护】
      //已经支持部分数据：关卡(LevelLink)、代币（Coin）、体力(Energy)、签到(CheckIn)
      // this.append(LevelLink, CoinLink, EnergyLink, CheckInLink);
      // MeVo.created = true;
   }

   /**
    * 初始化当前角色数据
    * @param id 平台登陆的id
    * @param nick 平台昵称
    * @returns 
    */
   public async init(): Promise<MeVo> {
      this.append(
         GameBgLink, GameBuildLink, BuildCollectionLink,
         StartViewLink, GameCoinLink, CatCatteryLink, GameTaskLink, DailyLink,
         ParkAScrewLink,
         SubgameAdvLink,ShootItemGameLink,ThrowItemGameLink
      );

      let onlineData = {}//await G_Data.server.getUserData();
      if (!CC_DEBUG && !cc.sys.isBrowser) {
         onlineData = await G_Data.server.getUserData();
      }
      let _initialData = this._data
      let data = app.storage.getUValue<object>(MeVo.ME_INFO_KEY, {});
      if (!data || Object.keys(data).length == 0) {
         if (Object.keys(onlineData).length > 0)
            this.parse(onlineData);
      } else {
         this.parse(data);

         //检查是否有新增配置数据
         for (const key in _initialData) {
            if (Object.prototype.hasOwnProperty.call(_initialData, key)) {
               const element = _initialData[key];
               if (this._data[key] == null || this._data[key] == undefined) {
                  this._data[key] = element
                  console.warn("新增配置数据", key, element)
                  this._savePlayerInfo()
               }
            }
         }
      }


      this.catCattery.IsTest = false

      this.updateLoginDay()
      //更新时间
      if (this._data.firstLoginTime == 0) {
         this.isFirstLogin = true;
         this._data.firstLoginTime = G_Data.server.time
      }
      console.log("第一次登录时间:", this.printTime(this._data.firstLoginTime))
      this.isNewDayReset()
      this.lastLoginTime = G_Data.server.time

      this.offUpdated(this, this._savePlayerInfo);
      this.onUpdated(this, this._savePlayerInfo);
      this._savePlayerInfo();

      this.initEmun()
      return this;
   }

   printTime(time) {
      //时间戳转换年月日时分秒
      let date = new Date(time);
      let year = date.getFullYear();
      let month = date.getMonth() + 1;
      let day = date.getDate();
      let hour = date.getHours();
      let minute = date.getMinutes();
      let second = date.getSeconds();
      return "当前时间：" + year + "年" + month + "月" + day + "日" + hour + "时" + minute + "分" + second + "秒"
   }

   initEmun() {
      this.linkEnum = [
         { type: GameType.parkAndScrew, link: this.parkAScrew },
         // { type: GameType.refueling, link: this.refueling },
         // { type: GameType.shark, link: this.shark },
         // { type: GameType.drawLinePark, link: this.drawLinePark },
         // { type: GameType.superFindWord, link: this.superFindWord },
         // { type: GameType.superScrewClassify, link: this.superScrewClassify },
         // { type: GameType.roomElimination, link: this.roomElimination },
         // { type: GameType.turtleCollision, link: this.turtleCollision },
         { type: GameType.throwItemGame, link: this.throwItemGame },
         { type: GameType.shootItemGame, link: this.shootItemGame },
      ];

   }

   clearData() {
      app.storage.removeGValue(StorageCommonKey.DEFAULT_USERID_KEY)
      app.storage.setUValue(MeVo.ME_INFO_KEY, {});
      this.reset();
      this._savePlayerInfo();
   }

   private _initNewUserData(): void {
      //默认解锁第一个关卡
      // let firstLevel: Levels = G_Config.level.findData(0);
      // firstLevel && this.level.unlockLevel(firstLevel.id);
   }

   getGameIDByType(type: GameType) {
      return type * 1000;
   }

   /**
    * 关卡数据
    */
   public get level(): LevelLink {
      return this.child("level");
   }

   /**
    * 是否为新玩家
    */
   public get isNewer(): boolean {
      return this.isFirstLogin
   }

   public get firstLoginTime(): number {
      return this._data.firstLoginTime
   }

   public get parkAScrew(): ParkAScrewLink {
      return this.child("parkAScrew");
   }

   public get build(): GameBuildLink {
      return this.child('build');
   }

   public get buildCollection(): BuildCollectionLink {
      return this.child('buildCollection');
   }

   public get bg(): GameBgLink {
      return this.child('gameBg');
   }

   public get subgameAdv(): SubgameAdvLink {
      return this.child('subgameAdv');
   }

   public get coin(): GameCoinLink {
      return this.child('coin');
   }

   public get startView(): StartViewLink {
      return this.child('startView');
   }

   public get catCattery(): CatCatteryLink {
      return this.child("catCattery")
   }

   public get gameTask(): GameTaskLink {
      return this.child("gameTask")
   }

   public get daily(): DailyLink {
      return this.child("daily")
   }

   public get throwItemGame(): ThrowItemGameLink {
      return this.child("throwItemGame")
   }

   public get shootItemGame(): ShootItemGameLink {
      return this.child("shootItemGame")
   }

   public get shop(): CatShopLink {
      return this.child("shop")
   }

   public get catPretend(): CatPretendLink {
      return this.child("catPretend")
   }



   private _countdown: Recover;
   public get countdown(): Recover {
      if (this.gameLink['countdown']) {
         return this.gameLink['countdown'];
      }
      else if (!this._countdown) {
         this._countdown = new Recover();
      }
      return this._countdown;
   }


   get userName() {
      return this._data.userName
   }
   set userName(value) {
      this._data.userName = value
   }

   public get nick(): string {
      return this._data.nick;
   }
   public set nick(nick: string) {
      this._data.nick = nick;
   }
   
   protected _restSelfData(): void {

   }

   /**
    * 强制保存缓存数据
    * @param data 
    */
   public forceSaveCache() {
      app.storage.forceSaveCache()
   }

   /**保存存档 */
   private _savePlayerInfo() {
      this._data.lastUpdate = G_Data.server.time;
      G_Data.server.saveUserData(this);
      app.storage.setUValue(MeVo.ME_INFO_KEY, this.toObject());
   }

   /**当前游戏类型 */
   private _gameType: GameType = null

   public get gameType(): GameType {
      return this._gameType
   }

   public linkEnum: { type: GameType; link: GameLinkInterface; }[] = [];
   public get gameLink(): GameLinkInterface {
      let info = this.linkEnum.find(it => it.type == this.gameType);
      if (info) {
         return info.link;
      }
      return this.parkAScrew;
   }

   /** 获取当前link */
   getLinkByType(type: GameType): GameLinkInterface {
      let info = this.linkEnum.find(it => it.type == type);
      if (info) {
         return info.link;
      }
      return null;
   }

   public startGameByType(type: GameType, lvId?: number) {
      if (type) {
         this._gameType = type;
      }
      return this.gameLink.startLevel(lvId);
   }

   public get levelInfo(): BaseLevelInfo {
      return this.gameLink.levelInfo;
   }

   public get todaySigned(): boolean {
      return this._data.todaySigned
   }

   public set todaySigned(signed: boolean) {
      this._data.todaySigned = signed
      this.updated("todaySigned", signed, signed)
   }

   public get lastLoginTime(): number {
      return this._data.lastLoginTime
   }
   public set lastLoginTime(v: number) {
      this._data.lastLoginTime = v;
      this.updated("lastLoginTime", v, v)
   }

   /**
     * 关卡解锁列表
     */
   public get unlockLevels(): number[] {
      return this.gameLink.unlocks as number[];
   }

   /**
    * 解锁关卡
    * @param level 目标关卡
    */
   public unlockLevel(level: number): void {
      this.gameLink.unlockLevel(level);
   }

   /**
    * 关卡是否解锁
    * @param level 目标关卡 
    * @returns 
    */
   public isUnlock(level: number): boolean {
      return this.gameLink.isUnlock(level);
   }

   /**
    * 通关关卡列表
    */
   public get passLevels(): number[] {
      return this.gameLink.passLevels as number[];
   }

   /**
    * 关卡是否通关
    * @param level 目标关卡
    * @returns 
    */
   public isPass(level: number): boolean {
      return this.gameLink.isPass(level);
   }

   /**
    * 保存通关关卡
    * @param level 目标关卡
    */
   public passLevel(level: number): void {
      this.gameLink.passLevel(level);
   }

   /** 检查后加的数据，没有手动添加默认值 */
   public updateDefData(defData, data) {
      let keys = Object.keys(defData);
      for (let key of keys) {
         if (!(key in data)) {
            data[key] = defData[key];
         }
      }
   }
   /**
      * 解锁关卡
      * @param level 目标关卡
      */
   public get isAdv() {
      return this.gameLink.isAdv;
   }

   public setGameType(type: GameType) {
      if (type) {
         this._gameType = type;
      }
   }

   /** 上次解锁全部副玩法时间 */
   set lastUnlockAllTime(time: number) {
      this._data.lastUnlockAllTime = time;
   }

   get lastUnlockAllTime() {
      return this._data.lastUnlockAllTime;
   }

   readonly _unlockAdLimit: number = 3;
   addUnlockAdNum() {
      this._data.unlockAdTime += 1;
      if (this._data.unlockAdTime >= this._unlockAdLimit) {
         this.lastUnlockAllTime = G_Data.server.time;
      }
      this._savePlayerInfo();
   }

   /**新的一天重置信息 */
   public isNewDayReset() {
      let lastDay = Math.floor(this.lastLoginTime / (24 * 60 * 60 * 1000));
      let today = Math.floor(Date.now() / (24 * 60 * 60 * 1000));
      if (lastDay < today) {
         let time = Date.now();
         this.lastLoginTime = time
         this._savePlayerInfo()

         console.log("新的一天重置信息")
         G_Data.me.gameTask.reset()
         G_Data.me.gameTask.resetDailyTask()
         G_Data.me.shop.resetDailyLimit()
         G_Data.me.catCattery.resetCatInteractiveRewardTime()
      }
   }

   updateLoginDay() {
      console.log("上次登录时间:", this.printTime(this._data.lastLoginTime))
      console.log("当前登录时间:", this.printTime(G_Data.server.time))
      if (Math.floor(this._data.lastLoginTime / (24 * 60 * 60 * 1000)) != Math.floor(G_Data.server.time / (24 * 60 * 60 * 1000))) {
         this._data.loginDays = this._data.loginDays + 1;
      }
      console.log("登录天数", this._data.loginDays);
   }

   public getLoginDay(): number {
      // console.log("登录天数", this._data.loginDays);
      return this._data.loginDays;
   }
}